package dao

import (
	"a-app/domain/entity"
	"a-common/constant"
	dom "a-common/domain"
	"a-common/utils"
	"errors"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	userDaoTemp *UserDao
	userDaoOnce sync.Once
)

type UserDao struct{}

func NewAppUserDao() *UserDao {
	userDaoOnce.Do(func() {
		userDaoTemp = &UserDao{}
	})
	return userDaoTemp
}

// List 列表
func (m *UserDao) List(args *entity.UserDto, isExport bool) (dom.PageVo, error) {
	// 构建查询条件
	query := pgCli.Table(&entity.AppUser{}).Where("1 = 1")
	if args.UserName != "" {
		query.And("username = ?", args.UserName)
	}
	if args.Phonenumber != "" {
		query.And("phonenumber = ?", args.Phonenumber)
	}
	if args.Status != "" {
		query.And("status = ?", args.Status)
	}
	if args.Params.BeginTime != "" && args.Params.EndTime != "" {
		query.And("created_at BETWEEN ? AND ?", args.Params.BeginTime, args.Params.EndTime)
	}
	if args.PageNum != 0 && args.PageSize != 0 {
		query.Limit(args.PageSize, (args.PageNum-1)*args.PageSize)
	}
	// 查询
	var vPage dom.PageVo
	if isExport {
		var rows []entity.AppUserExportVo
		total, err := query.Asc("user_id").FindAndCount(&rows)
		if err != nil {
			return vPage, err
		}
		vPage.Rows = rows
		vPage.Total = total
	} else {
		var rows []entity.AppUserPageVo
		total, err := query.Asc("user_id").FindAndCount(&rows)
		if err != nil {
			return vPage, err
		}
		vPage.Rows = rows
		vPage.Total = total
	}
	vPage.PageNum = args.PageNum
	vPage.PageSize = args.PageSize
	return vPage, nil
}

// Get 查
func (m *UserDao) Get(id int64) (entity.AppUserPageVo, error) {
	var v entity.AppUserPageVo
	_, err := pgCli.Table(&entity.AppUser{}).ID(id).Get(&v)
	return v, err
}

// Add 增
func (m *UserDao) Add(args *entity.UserDto) error {
	session := pgCli.NewSession()
	defer session.Close()
	if err := session.Begin(); err != nil {
		return err
	}

	// 加密
	pwd, err := utils.NewCryptUtils().EnCrypt(args.Password)
	if err != nil {
		return err
	}

	var appUser = &entity.AppUser{
		UserName:    args.UserName,
		NickName:    args.NickName,
		Phonenumber: args.Phonenumber,
		Email:       args.Email,
		Sex:         args.Sex,
		Password:    pwd,
		Status:      args.Status,
		DelFlag:     constant.USER_NORMAL,
		BaseStruct: dom.BaseStruct{
			CreatedBy: args.CreatedBy,
			UpdatedBy: args.CreatedBy,
			Remark:    args.Remark,
		},
	}
	if _, err := pgCli.Insert(appUser); err != nil {
		return err
	}
	if appUser.UserId == 0 {
		return errors.New("新增失败")
	}
	return session.Commit()
}

// Edit 改
func (m *UserDao) Edit(args *entity.UserDto) error {
	session := pgCli.NewSession()
	defer session.Close()
	if err := session.Begin(); err != nil {
		return err
	}

	if _, err := pgCli.ID(args.UserId).Update(&entity.AppUser{
		UserName:    args.UserName,
		NickName:    args.NickName,
		Phonenumber: args.Phonenumber,
		Email:       args.Email,
		Sex:         args.Sex,
		Status:      args.Status,
		BaseStruct: dom.BaseStruct{
			UpdatedBy: args.UpdatedBy,
			Remark:    args.Remark,
		},
	}); err != nil {
		return err
	}

	return session.Commit()
}

// Del 删
func (m *UserDao) Del(ids string) (int64, error) {
	return pgCli.In("user_id", strings.Split(ids, `,`)).Delete(&entity.AppUser{})
}

// EditByIpAndTime 更新IP和登陆时间
func (m *UserDao) EditByIpAndTime(userId int64, ip string, time time.Time) error {
	_, err := pgCli.Table(&entity.AppUser{}).ID(userId).NoAutoTime().Update(
		map[string]interface{}{
			"login_ip":        ip,
			"last_login_time": time,
		})
	return err
}

// EditByAvatar 更新用户头像路径
func (m *UserDao) EditByAvatar(userId int64, url string) error {
	_, err := pgCli.Table(&entity.AppUser{}).ID(userId).Update(
		&entity.AppUser{
			Avatar: url,
		})
	return err
}

// ChangeStatus 改变状态
func (m *UserDao) ChangeStatus(userId int64, status string, updateBy string) (int64, error) {
	return pgCli.ID(userId).Update(&entity.AppUser{
		Status: status,
		BaseStruct: dom.BaseStruct{
			UpdatedBy: updateBy,
		},
	})
}

// UpdatePwd 更新密码
func (m *UserDao) UpdatePwd(userId int64, password string, updateBy string) (int64, error) {
	password, err := utils.NewCryptUtils().EnCrypt(password)
	if err != nil {
		return 0, err
	}
	return pgCli.ID(userId).Update(&entity.AppUser{
		Password: password,
		BaseStruct: dom.BaseStruct{
			UpdatedBy: updateBy,
		},
	})
}

// CheckNickNameUnique 校验用户昵称是否唯一
func (m *UserDao) CheckNickNameUnique(nikeName string, userId int64) (bool, error) {
	query := pgCli.Where("1 = 1")
	if userId != 0 {
		query.And("user_id != ?", userId)
	}
	return query.Exist(&entity.AppUser{
		NickName: nikeName,
	})
}

// CheckUserNameUnique 校验用户名称是否唯一
func (m *UserDao) CheckUserNameUnique(userName string, userId int64) (bool, error) {
	query := pgCli.Where("1 = 1")
	if userId != 0 {
		query.And("user_id != ?", userId)
	}
	return query.Exist(&entity.AppUser{
		UserName: userName,
	})
}

// CheckPhoneUnique 校验手机号码是否唯一
func (m *UserDao) CheckPhoneUnique(phonenumber string, userId int64) (bool, error) {
	query := pgCli.Where("1 = 1")
	if userId != 0 {
		query.And("user_id != ?", userId)
	}
	return query.Exist(&entity.AppUser{
		Phonenumber: phonenumber,
	})
}

// CheckEmailUnique 校验email是否唯一
func (m *UserDao) CheckEmailUnique(email string, userId int64) (bool, error) {
	query := pgCli.Where("1 = 1")
	if userId != 0 {
		query.And("user_id != ?", userId)
	}
	return query.Exist(&entity.AppUser{
		Email: email,
	})
}

// ImportData 导入
func (m *UserDao) ImportData(updateSupport int, importList []entity.AppUserImportVo, createdBy string) (string, error) {
	session := pgCli.NewSession()
	defer session.Close()
	if err := session.Begin(); err != nil {
		return "", err
	}

	successNum := int64(0)
	failureNum := int64(0)
	successMsg := ""
	failureMsg := ""
	msg := ""
	for _, t := range importList {
		if t.UserName == constant.ADMIN {
			return msg, errors.New("不允许操作超级管理员角色")
		}

		// 查询是否存在用户名
		has, err := m.CheckUserNameUnique(t.UserName, 0)
		if err != nil {
			return msg, err
		}

		if t.Status == "正常" {
			t.Status = constant.USER_NORMAL
		} else {
			t.Status = constant.USER_DISABLE
		}

		if t.Sex == "男" {
			t.Sex = "0"
		} else if t.Sex == "女" {
			t.Sex = "1"
		} else {
			t.Sex = "2"
		}

		// 加密
		pwd, err := utils.NewCryptUtils().EnCrypt("123456")
		if err != nil {
			return msg, errors.New("不允许操作超级管理员角色")
		}
		var appUser = &entity.AppUser{
			UserName:    t.UserName,
			NickName:    t.NickName,
			Phonenumber: t.Phonenumber,
			Email:       t.Email,
			Sex:         t.Sex,
			Password:    pwd,
			Status:      t.Status,
			DelFlag:     constant.USER_NORMAL,
			BaseStruct: dom.BaseStruct{
				CreatedBy: createdBy,
				UpdatedBy: createdBy,
			},
		}

		if !has {
			if _, err := pgCli.Insert(appUser); err != nil {
				return msg, err
			}
			if appUser.UserId == 0 {
				return msg, errors.New("不允许操作超级管理员角色")
			}
			successNum = successNum + 1
			successMsg = successMsg + "<br/>" + strconv.FormatInt(successNum, 10) + "、账号 " + t.UserName + " 更新成功"
		} else if updateSupport == 1 {
			// 更新
			if _, err := pgCli.Where("username = ?", t.UserName).Update(appUser); err != nil {
				return msg, err
			}
			successNum = successNum + 1
			successMsg = successMsg + "<br/>" + strconv.FormatInt(successNum, 10) + "、账号 " + t.UserName + " 更新成功"
		} else {
			// 已存在
			failureNum = failureNum + 1
			failureMsg = failureMsg + "<br/>" + strconv.FormatInt(failureNum, 10) + "、账号 " + t.UserName + " 已存在"
		}
	}

	if failureNum > 0 {
		msg = "很抱歉，导入失败！共 " + strconv.FormatInt(failureNum, 10) + " 条数据格式不正确，错误如下：" + failureMsg
	} else {
		msg = "恭喜您，数据已全部导入成功！共 " + strconv.FormatInt(successNum, 10) + " 条，数据如下：" + successMsg
	}

	return msg, session.Commit()
}

// GetSelectList 获取用户下拉列表
func (m *UserDao) GetSelectList() ([]entity.AppUserSelectListVo, error) {
	list := make([]entity.AppUserSelectListVo, 0)
	err := pgCli.Table(&entity.AppUser{}).Cols("user_id", "username").Where("status = '0'").Asc("user_id").Find(&list)
	return list, err
}
